/* ****************************************************************************
 *
 * Copyright (c) Microsoft Corporation. 
 *
 * This source code is subject to terms and conditions of the Microsoft Public License. A 
 * copy of the license can be found in the License.html file at the root of this distribution. If 
 * you cannot locate the  Microsoft Public License, please send an email to 
 * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound 
 * by the terms of the Microsoft Public License.
 *
 * You must not remove this notice, or any other, from this software.
 *
 *
 * ***************************************************************************/

using System.Linq.Expressions;
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Security;

namespace Microsoft.Scripting {

    /// <summary>
    /// Abstracts system operations that are used by DLR and could potentially be platform specific.
    /// The host can implement its PAL to adapt DLR to the platform it is running on.
    /// For example, the Silverlight host adapts some file operations to work against files on the server.
    /// </summary>
    [Serializable]
    public class PlatformAdaptationLayer {
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")]
        public static readonly PlatformAdaptationLayer Default = new PlatformAdaptationLayer();

        #region Assembly Loading

        public virtual Assembly LoadAssembly(string name) {
            return Assembly.Load(name);
        }

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2001:AvoidCallingProblematicMethods", MessageId = "System.Reflection.Assembly.LoadFile")]
        public virtual Assembly LoadAssemblyFromPath(string path) {
            return Assembly.LoadFile(path);
        }

        public virtual void TerminateScriptExecution(int exitCode) {
            System.Environment.Exit(exitCode);
        }

        #endregion

        #region Virtual File System

        public virtual StringComparer PathComparer {
            get {
                return StringComparer.Ordinal;
            }
        }

        public virtual bool FileExists(string path) {
            return File.Exists(path);
        }

        public virtual bool DirectoryExists(string path) {
            return Directory.Exists(path);
        }

        public virtual Stream OpenInputFileStream(string path, FileMode mode, FileAccess access, FileShare share) {
            return new FileStream(path, mode, access, share);
        }

        public virtual Stream OpenInputFileStream(string path, FileMode mode, FileAccess access, FileShare share, int bufferSize) {
            return new FileStream(path, mode, access, share, bufferSize);
        }

        public virtual Stream OpenInputFileStream(string path) {
            return new FileStream(path, FileMode.Open, FileAccess.Read);
        }

        public virtual Stream OpenOutputFileStream(string path) {
            return new FileStream(path, FileMode.Create, FileAccess.Write);
        }

        public virtual string[] GetFiles(string path, string searchPattern) {
            return Directory.GetFiles(path, searchPattern);            
        }

        public virtual string[] GetDirectories(string path, string searchPattern) {
            return Directory.GetDirectories(path, searchPattern);
        }

        /// <exception cref="ArgumentException">Invalid path.</exception>
        public virtual string GetFullPath(string path) {
            try {
                return Path.GetFullPath(path);
            } catch (Exception) {
                throw Error.InvalidPath();
            }
        }

        public virtual string GetFileName(string file) {
            return Path.GetFileName(file);
        }

        /// <exception cref="ArgumentException">Invalid path.</exception>
        public virtual bool IsAbsolutePath(string path) {
            // GetPathRoot returns either :
            // "" -> relative to the current dir
            // "\" -> relative to the drive of the current dir
            // "X:" -> relative to the current dir, possibly on a different drive
            // "X:\" -> absolute
            return
                Environment.OSVersion.Platform != PlatformID.Unix && Path.GetPathRoot(path).EndsWith(@":\") ||
                Environment.OSVersion.Platform == PlatformID.Unix && Path.IsPathRooted(path);
        }

        public virtual string CurrentDirectory {
            get {
                return Environment.CurrentDirectory;
            }
        }

        #endregion

        #region Environmental Variables

        public virtual string GetEnvironmentVariable(string key) {
            return Environment.GetEnvironmentVariable(key);
        }

        public virtual void SetEnvironmentVariable(string key, string value) {
            Environment.SetEnvironmentVariable(key, value);
        }

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")]
        public virtual System.Collections.IDictionary GetEnvironmentVariables() {
            return Environment.GetEnvironmentVariables();
        }

        #endregion
    }
}
